/*
 *  testClassChunkList.cpp
 *  kangmodb
 *
 *  Created by 강모 김 on 11. 5. 2..
 *  Copyright 2011 강모소프트. All rights reserved.
 *
 */
#include "gtest/gtest.h"

#include "kangmodb.h"
#include "testCommon.h"
#include "chunkList.h"

/** @brief Test stgChunkList class 
 */
class testClassChunkList : public testing::Test {
protected:  // You should make the members protected s.t. they can be
	// accessed from sub-classes.
	
	// virtual void SetUp() will be called before each test is run.  You
	// should define it if you need to initialize the varaibles.
	// Otherwise, this can be skipped.
	virtual void SetUp() {
	}
	
	// virtual void TearDown() will be called after each test is run.
	// You should define it if there is cleanup work to do.  Otherwise,
	// you don't have to provide it.
	//
	virtual void TearDown() {
	}
protected:
};

// Verify iteration assuming that the number of maximum added chunks are 3. 
static void verify_chunk_iteration( stgChunkList & chunkList, int expectedIterCount) 
{
	void * chunk;
	ASSERT_TRUE( chunkList.initIteration() == 0 );
	for (int i=0; i<expectedIterCount; i++)
	{
		ASSERT_TRUE( chunkList.iterate(&chunk) == 0 );
		ASSERT_TRUE( chunk != NULL );
		EXPECT_TRUE( ((char*)chunk)[ stgChunkList::CHUNK_UNUSABLE_SIZE ] == (char)('1'+i) );
	}
	ASSERT_TRUE( chunkList.iterate(&chunk) == 0 );
	EXPECT_TRUE( chunk == NULL );


	ASSERT_TRUE( chunkList.initReverseIteration() == 0 );

	for (int i=expectedIterCount-1; i>=0; i--)
	{
		ASSERT_TRUE( chunkList.reverseIterate(&chunk) == 0 );
		ASSERT_TRUE( chunk != NULL );
		EXPECT_TRUE( ((char*)chunk)[ stgChunkList::CHUNK_UNUSABLE_SIZE ] == (char)('1'+i) );
	}
	ASSERT_TRUE( chunkList.reverseIterate(&chunk) == 0 );
	EXPECT_TRUE( chunk == NULL );
} 

TEST_F(testClassChunkList, Basic) {
	char chunk1[64]={0,};
	char chunk2[64]={0,};
	char chunk3[64]={0,};
	
	stgChunkList chunkList;
	
	// The chunk list is empty.
	EXPECT_TRUE( chunkList.empty() );
	// Add the first chunk.
	{
		ASSERT_TRUE( chunkList.addChunk(chunk1) == 0 );
		chunk1[ stgChunkList::CHUNK_UNUSABLE_SIZE ] = '1';
		// The chunk list is not empty any more.
		EXPECT_FALSE( chunkList.empty() );
		
		// Only one chunk is iterated.
		verify_chunk_iteration(chunkList, 1);
	}

	// Remove the first chunk.
	{
		ASSERT_TRUE( chunkList.removeChunk(chunk1) == 0 );
		// The chunk list is empty.
		EXPECT_TRUE( chunkList.empty() );
		
		// No chunk is iterated.
		verify_chunk_iteration(chunkList, 0);
	}
	
	// Add the first chunk again
	{
		ASSERT_TRUE( chunkList.addChunk(chunk1) == 0 );
		chunk1[ stgChunkList::CHUNK_UNUSABLE_SIZE ] = '1';
		
		// Only one chunk is iterated.
		verify_chunk_iteration(chunkList, 1);
	}
	
	for (int i=0; i<2; i++ ) // Add, Remove the second chunk. Repeat twice.
	{
		// Add the second chunk.
		{
			ASSERT_TRUE( chunkList.addChunk(chunk2) == 0 );
			chunk2[ stgChunkList::CHUNK_UNUSABLE_SIZE ] = '2';
			// The chunk list is not empty any more.
			EXPECT_FALSE( chunkList.empty() );

			// Two chunks are iterated.
			verify_chunk_iteration(chunkList, 2);
		
		}
		
		// Remove the second chunk.
		{
			ASSERT_TRUE( chunkList.removeChunk(chunk2) == 0 );
			// The chunk list is not empty yet.
			EXPECT_FALSE( chunkList.empty() );
		
			// Only one chunk is iterated.
			verify_chunk_iteration(chunkList, 1);
		}
	}


	// Remove the first chunk.
	{
		ASSERT_TRUE( chunkList.removeChunk(chunk1) == 0 );
		// The chunk list is empty.
		EXPECT_TRUE( chunkList.empty() );
		
		// No chunk is iterated.
		verify_chunk_iteration(chunkList, 0);
	}

	// Add the first/second chunk again
	{
		ASSERT_TRUE( chunkList.addChunk(chunk1) == 0 );
		chunk1[ stgChunkList::CHUNK_UNUSABLE_SIZE ] = '1';
		ASSERT_TRUE( chunkList.addChunk(chunk2) == 0 );
		chunk2[ stgChunkList::CHUNK_UNUSABLE_SIZE ] = '2';
		
		// Two chunks are iterated.
		verify_chunk_iteration(chunkList, 2);
	}

	for (int i=0; i<2; i++ ) // Add, Remove the third chunk. Repeat twice.
	{
		// Add the third chunk.
		{
			ASSERT_TRUE( chunkList.addChunk(chunk3) == 0 );
			chunk3[ stgChunkList::CHUNK_UNUSABLE_SIZE ] = '3';
			// The chunk list is not empty any more.
			EXPECT_FALSE( chunkList.empty() );

			// Three chunks are iterated.
			verify_chunk_iteration(chunkList, 3);
		
		}
		
		// Remove the third chunk.
		{
			ASSERT_TRUE( chunkList.removeChunk(chunk3) == 0 );
			// The chunk list is not empty yet.
			EXPECT_FALSE( chunkList.empty() );
		
			// Two chunks are iterated.
			verify_chunk_iteration(chunkList, 2);
		}
	}
	
	// Remove the second chunk.
	{
		ASSERT_TRUE( chunkList.removeChunk(chunk2) == 0 );
		// The chunk list is not empty yet.
		EXPECT_FALSE( chunkList.empty() );
		
		// Only one chunk is iterated.
		verify_chunk_iteration(chunkList, 1);
	}
	
	// Remove the first chunk.
	{
		ASSERT_TRUE( chunkList.removeChunk(chunk1) == 0 );
		// The chunk list is empty.
		EXPECT_TRUE( chunkList.empty() );
		
		// No chunk is iterated.
		verify_chunk_iteration(chunkList, 0);
	}
}